package com.example.waimaiandroid.map;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.PoiDetailInfo;
import com.baidu.mapapi.search.core.PoiInfo;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.baidu.mapapi.search.poi.OnGetPoiSearchResultListener;
import com.baidu.mapapi.search.poi.PoiAddrInfo;
import com.baidu.mapapi.search.poi.PoiCitySearchOption;
import com.baidu.mapapi.search.poi.PoiDetailResult;
import com.baidu.mapapi.search.poi.PoiDetailSearchResult;
import com.baidu.mapapi.search.poi.PoiIndoorInfo;
import com.baidu.mapapi.search.poi.PoiIndoorResult;
import com.baidu.mapapi.search.poi.PoiResult;
import com.baidu.mapapi.search.poi.PoiSearch;
import com.baidu.mapapi.search.sug.OnGetSuggestionResultListener;
import com.baidu.mapapi.search.sug.SuggestionResult;
import com.baidu.mapapi.search.sug.SuggestionSearch;
import com.example.waimai.context.UserInfoContext;
import com.example.waimai.pojo.UserAddress;
import com.example.waimaiandroid.R;

import java.util.ArrayList;
import java.util.List;

/*
* 用户选择自己的收货地址
* */
public class ZdpMapView extends AppCompatActivity {
    // 定位使用
    private LocationClient mLocationClient  = null;
    private LocationClientOption mOption = null ; // 定位的一些属性的设置
    private MyLocationListener myListener = new MyLocationListener();
    private boolean isFirstLocation = true; // 是否为第一次定位
    private LatLng currentLatLng = null;

    //=======================================================================================
    // 地图显示

    private BaiduMap mBaiduMap = null; // 用于控制MapView的对象
    //=======================================================================================
    // 控件
    private MapView mMapView = null;  // 地图控件
    private TextView mTvCity = null; // 上方显示城市
    private EditText searchKeyWord = null ; // 关键字搜索
    // ListView
    private ListView lv_searchAddress; // 拖动地图时展示的地点
    private ListView lv_poiSearch; // 搜索框搜索时展示的地点
    private LinearLayout ll_mapView; // 地图所在布局
    private LinearLayout ll_poiSearch; // 搜索框搜索时布局
    private ImageView back;
    //=======================================================================================
    // 直接使用 POI 来搜索
    PoiSearch mPoiSearch = null;
    private int index = 0; // 分页
    private List<PoiInfo> poiInfoList = new ArrayList<>();
    private boolean ifFristToSearch = true;
    private Adapter_SearchAddress searchAddress = null;
    private Marker marker;
    private LatLng center; // 当前地图的中心点
    private GeoCoder geoCoder = null;
    private List<PoiInfo> reverseGeoCoderPoiInfoList = new ArrayList<>(); // 反向地理解析得到的poi

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //在使用SDK各组件之前初始化context信息，传入ApplicationContext
        SDKInitializer.initialize(getApplication());
        setContentView(R.layout.activity_map);
        // 初始化组件
        initView();
        // 开启定位服务
        initLocation();
        // 初始化 逆地址编码
        initGeoCoder();
        // 初始化 POI Search
        initPoiSearch();
        // 实现移动 显示
        initMovePoiSearch();

    }




    /*
    * 初始化逆地址编码
    * */
    private void initGeoCoder(){
        geoCoder = GeoCoder.newInstance();
        // 设置监听器
        geoCoder.setOnGetGeoCodeResultListener(new OnGetGeoCoderResultListener() {
            @Override
            public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {

            }

            // 逆地址编码
            @Override
            public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
                if (reverseGeoCodeResult == null || reverseGeoCodeResult.error != SearchResult.ERRORNO.NO_ERROR) {
                    //没有找到检索结果
                    return;
                } else {
                    ReverseGeoCodeResult.AddressComponent addressDetail = reverseGeoCodeResult.getAddressDetail();
                    mTvCity.setText(addressDetail.city);
                    if(reverseGeoCodeResult.getPoiList()!= null){
                        reverseGeoCoderPoiInfoList = reverseGeoCodeResult.getPoiList();
                    }

                    // 显示结果
                    initGeoResult();
                }
            }
        });
    }
    private void initGeoResult(){
        searchAddress = new Adapter_SearchAddress(reverseGeoCoderPoiInfoList,this,currentLatLng);
        lv_searchAddress.setAdapter(searchAddress);
    }

    /*
    * 移动地图，显示附近的点
    * */
    private void initMovePoiSearch(){
        // 对 baiduMap 监听
        mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {

            /**
             * 手势操作地图，设置地图状态等操作导致地图状态开始改变。
             * @param mapStatus 地图状态改变开始时的地图状态
             */
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus) {
            }

            /** 因某种操作导致地图状态开始改变。
             * @param mapStatus 地图状态改变开始时的地图状态
             * @param i 取值有：
             * 1：用户手势触发导致的地图状态改变,比如双击、拖拽、滑动底图
             * 2：SDK导致的地图状态改变, 比如点击缩放控件、指南针图标
             * 3：开发者调用,导致的地图状态改变
             */
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
                Log.e("地图状态", "地图状态改变开始时：" + i + "");
            }

            /**
             * 地图状态变化中
             * @param mapStatus 当前地图状态
             */
            @Override
            public void onMapStatusChange(MapStatus mapStatus) {
                // 滑动中需要改变一下 图标的位置
                LatLng latlng = mBaiduMap.getMapStatus().target;
                addMarker(latlng);
            }

            /**
             * 地图状态改变结束
             * @param mapStatus 地图状态改变结束后的地图状态
             */
            @Override
            public void onMapStatusChangeFinish(MapStatus mapStatus) {
                // 获取到中心点，需要改变一下当前位置吗？

                center = mapStatus.target;
                // 然后进行反向地理解析
                geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(center));
            }
        });
    }
    /**
     * 添加marker
     *
     * @param point Marker坐标点
     */
    private void addMarker(LatLng point) {
        if (marker != null) {
//            marker.remove();
            marker.setPosition(point);
        } else {
            //构建Marker图标
            BitmapDescriptor bitmap = BitmapDescriptorFactory
                    .fromResource(R.mipmap.location);
            //构建MarkerOption，用于在地图上添加Marker
            OverlayOptions option = new MarkerOptions()
                    .position(point)
                    .icon(bitmap);
            //在地图上添加Marker，并显示
            marker = (Marker) mBaiduMap.addOverlay(option);
        }
    }

    /*
    * 初始化组件
    * */
    private void initView(){
        mMapView = findViewById(R.id.bmapView);
        mBaiduMap = mMapView.getMap(); // 绑定要操作的地图控件
        mTvCity = findViewById(R.id.tv_city);
        searchKeyWord = findViewById(R.id.et_keyword);
        lv_searchAddress = findViewById(R.id.lv_searchAddress);
        lv_poiSearch = findViewById(R.id.lv_poiSearch);
        ll_mapView = findViewById(R.id.ll_mapView);
        ll_poiSearch = findViewById(R.id.ll_poiSearch);
        back  = findViewById(R.id.myTitle_back);
        // 设置一下返回 的监听器
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        // 监听输入框
        setListenerToEdit();

    }

    @Override
    protected void onStart() {
        super.onStart();
        String from = getIntent().getStringExtra("fromActivity");
        // 设置监听器
        lv_searchAddress.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent();
                PoiInfo poiInfo = (PoiInfo) searchAddress.getItem(position);
                if("addAddress".equals(from)){
                    // 生成 UserAddress信息
                    UserAddress userAddress = new UserAddress();
                    userAddress.setUserId(UserInfoContext.mUser.getId());
                    userAddress.setAddress(poiInfo.name);
                    userAddress.setLatitude( String.valueOf(poiInfo.getLocation().latitude));
                    userAddress.setLongitude(String.valueOf(poiInfo.getLocation().longitude));
                    Bundle bundle  = new Bundle();
                    bundle.putSerializable("UserAddress",userAddress);
                    intent.putExtras(bundle);
                }else{
                    // 获取到 数据，然后返回
                    UserInfoContext.currentAddr = poiInfo;
                    UserInfoContext.currentLatLng = poiInfo.getLocation();
                }
                // 返回一个 UserAddress
                setResult(1,intent);
                finish();
            }
        });
        lv_poiSearch.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent();
                PoiInfo poiInfo = (PoiInfo) searchAddress.getItem(position);
                if("addAddress".equals(from)){
                    // 生成 UserAddress信息
                    UserAddress userAddress = new UserAddress();
                    userAddress.setUserId(UserInfoContext.mUser.getId());
                    userAddress.setAddress(poiInfo.name);
                    userAddress.setLatitude(String.valueOf( poiInfo.getLocation().latitude));
                    userAddress.setLongitude(String.valueOf(poiInfo.getLocation().longitude));
                    Bundle bundle  = new Bundle();
                    bundle.putSerializable("UserAddress",userAddress);
                    intent.putExtras(bundle);
                }else{
                    // 获取到 数据，然后返回
                    UserInfoContext.currentAddr = poiInfo;
                }
                // 返回一个 UserAddress
                setResult(1,intent);
                finish();
            }
        });
    }

    // 监听输入框
    private void setListenerToEdit(){

        searchKeyWord.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {
                String key = s.toString();
                if(key.length() <=0){
                    // 关闭搜索
                    showMap();
                    return ;
                }
                // 开启进行 搜索框搜索
                startPoiSearch(key);
            }
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

        });
    }

    private void startPoiSearch(String keyword){
        String city = mTvCity.getText().toString();
        //city = city.substring(0,city.length()-1);
        mPoiSearch.searchInCity(new PoiCitySearchOption()
                .city(city)
                .keyword(keyword)
                .pageNum(index)); // 分页还未实现
    }

    /*
    * 初始化  POI Search 相关
    * */
    private void initPoiSearch(){
         mPoiSearch = PoiSearch.newInstance();
         mPoiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
             // 这边得到的信息是全国的。 不是在这个城市内的
             @Override
             public void onGetPoiResult(PoiResult poiResult) {
                 if(poiResult.error == SearchResult.ERRORNO.NO_ERROR){
                     // 没有错误
                     poiInfoList = poiResult.getAllPoi();
                     showSearch();
                     initSearchAdapter();
                 }
             }
             @Override
             public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
             }
             @Override
             public void onGetPoiDetailResult(PoiDetailSearchResult poiDetailSearchResult) {
               //  List<PoiDetailInfo> poiDetailInfoList = poiDetailSearchResult.getPoiDetailInfoList();
             }
             @Override
             public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
                // List<PoiIndoorInfo> arrayPoiInfo = poiIndoorResult.getArrayPoiInfo();
             }
         });

    }

    /*
    * 初始化 Adapter
    * */
    private void initSearchAdapter(){
        searchAddress = new Adapter_SearchAddress(poiInfoList,this,currentLatLng);
        lv_poiSearch.setAdapter(searchAddress);
    }

    /*
    * 初始化定位相关的信息
    * */
    private void initLocation(){
        // 开启 地图的定位图层
        mBaiduMap.setMyLocationEnabled(true);
        // 声明LocationClient类
        mLocationClient = new LocationClient(getApplicationContext());
        // 初始化 LocationOption
        initLocationOption();
        mLocationClient.setLocOption(mOption);
        // 注册监听函数
        mLocationClient.registerLocationListener(myListener);
        mLocationClient.start(); // 开启定位服务
    }
    private void initLocationOption(){
        mOption = new LocationClientOption();
        /*
         * 设置定位模式     默认高精度
         * Hight_accuracy : 高精度
         * Battery_Saving : 低功耗
         *  Device_Sensors : 仅使用设备
         * */
        mOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        /*
         * 设置返回的经纬度的类型 ：默认 GCJ02
         * GCJ02 : 国测局坐标
         * BD09LL : 百度经纬度坐标
         * BD09 : 百度墨卡托坐标
         * 海外地区定位，无需设置坐标类型，统一返回WGS84类型坐标
         * */
        mOption.setCoorType("bd09ll");
        /*
         * 设置发起定位请求的间隔，Int类型，单位ms
         * 设置为0 ， 则代表单次定位，只定位一次，默认为0
         * 设置为非0，则1000以上才有效
         * */
        mOption.setScanSpan(0);
        /*
         * 设置是否选择 GPS 默认为false
         * 使用高精度和仅使用设备两种定位模式的话，必须设置为true
         * */
        mOption.setOpenGps(true);

        /*设置是否当GPS有效时按照 1s/1次频率输出GPS结果，默认为False*/
        mOption.setLocationNotify(false);

        /*定位SDK内部是一个Service ，并放到了独立进程
         * 设置是否在stop的时候杀死这个进程，默认（建议）不杀死
         * */
        mOption.setIgnoreKillProcess(false);

        /*
         * 设置是否收集 Crash信息，默认收集，
         * */
        mOption.SetIgnoreCacheException(false);
        /*
         * v7.2版本新增的功能
         * 如果设置了该接口，首次启动定位时，会先判断当前wifi 是否超出有效期，如果超出有效期，会先重新扫描wifi，然后定位
         * */
        mOption.setWifiCacheTimeOut(5 * 60 * 1000);

        /*
         * 设置是否需要过滤GPS仿真结果，默认需要，
         * */
        mOption.setEnableSimulateGps(false);

        /*
         * 显示地理位置信息 （false 就无法显示了） 国家 位置
         * */
        mOption.setIsNeedAddress(true);
    }

    /**
     * 监听当前位置
     */
    public class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            //mapView 销毁后不在处理新接收的位置
            if (location == null || mMapView == null) {
                return;
            }
            if (location.getLocType() == BDLocation.TypeGpsLocation
                    || location.getLocType() == BDLocation.TypeNetWorkLocation) {
                Log.e("定位信息", "当前“我”的位置：" + location.getAddrStr());
                navigateTo(location); // 在地图上定位我的位置
            }
        }
    }

    /*
    * 地图上跳转到当前位置
    *
    * */
    private void navigateTo(BDLocation location){
        if(isFirstLocation){ // 第一次定位
              //封装经纬度的对象
            currentLatLng = new LatLng(location.getLatitude(),location.getLongitude());
            // 通过MapStatusUpdate 对象来更新地图  由一个工厂类获得该对象 ，传入新的经纬度
            MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(currentLatLng);
            // 更新地图
            mBaiduMap.animateMapStatus(update);
            // 缩放地图
            update = MapStatusUpdateFactory.zoomTo(16f);
            mBaiduMap.animateMapStatus(update);
            isFirstLocation = false;
            // 设置一下城市的位置
            mTvCity.setText(location.getCity());
            // 初始化一下数据
            geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(currentLatLng));
        }

        // 标识当前位置  显示“我”的位置
        // 当前位置信息的构建者
        MyLocationData.Builder locationBuilder = new MyLocationData.Builder();
        // 设置位置信息
        locationBuilder.longitude(location.getLongitude());
        locationBuilder.latitude(location.getLatitude());
        // 设置方向
        locationBuilder.direction(location.getDirection());
        // 初始化一个 位置信息对象，构建出一个位置信息 （根据刚才设置的位置信息）
        MyLocationData locationData = locationBuilder.build();
        // 标识出当前的位置信息
        mBaiduMap.setMyLocationData(locationData);

       /* MyLocationData locData = new MyLocationData.Builder()
                .accuracy(location.getRadius())
                // 此处设置开发者获取到的方向信息，顺时针0-360
                .direction(location.getDirection()).latitude(location.getLatitude())
                .longitude(location.getLongitude()).build();
        mBaiduMap.setMyLocationData(locData);*/

    }

    /*
    * 显示地图 隐藏搜索结果
    * */
    private void showMap(){
        ll_mapView.setVisibility(View.VISIBLE);
        ll_poiSearch.setVisibility(View.GONE);
    }

    /*
    * 显示搜索结果，隐藏地图
    * */
    private void showSearch(){
        ll_mapView.setVisibility(View.GONE);
        ll_poiSearch.setVisibility(View.VISIBLE);
    }


}